﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using System.Drawing.Imaging;
using System.Reflection;

namespace MedicWave.Visualization3d
{


    class Scatterplot3DControl : DXControl
    {

        struct PlotZoom
        {
            public float Subset;
            public float XOffset;
            public float YOffset;
            public float ZOffset;
        }


        private PlotZoom m_PlotZoom;
        private Microsoft.DirectX.Direct3D.Font m_debugFont = null;
        private Microsoft.DirectX.Direct3D.Font m_LoadingFont = null;
        private Microsoft.DirectX.Direct3D.Font m_PlotTitleFont = null;
        private Microsoft.DirectX.Direct3D.Font m_PlotSubtitleFont = null;
        private Microsoft.DirectX.Direct3D.Font m_LegendFont = null;
        private Sprite m_spriteObject = null;
        private int m_iFrameNumber = 0;


        //////////////////////////////////////////////////////////////////////////
        //camera data
        private float m_fMouseRotateSensitivity = 100f;
        private Point m_previousMousePosition;
        private float m_fCameraRotationY = 0;
        private float m_fCameraRotationX = 0;
        private float m_fMaxCameraDistance = 220;
        private float m_fCurrentCameraDistance = 220;


        private float m_fMinCameraDistance = 100f;
        private Vector3 m_vInitialCameraPos = new Vector3(-50.0f, 20f, 180.0f);
        private Vector3 m_vCameraPos = new Vector3(-50f, 0f, 200.0f);
        private Vector3 m_vInitialLookAt = new Vector3(-20, 20, 0);
        private Vector3 m_vLookAt = new Vector3(-50, 0, 0);
        private Vector3 m_vPlotArea = new Vector3(100, 70, 100);
        private Vector3 m_vPlotPosition = new Vector3(0, 0, 0);

        private Matrix m_ProjectionMatrix;
        private Matrix m_ViewMatrix;
        private Matrix m_PlotTransform;



        private const float m_fMinSubset = 0.05f;

        //PlotData
        private Mesh m_PlotPointMesh;
        private Mesh m_PlotSphereMesh;
        private Material m_SurfaceMaterial;


        BackgroundWorker m_DataLoader = new BackgroundWorker();
        //Form m_LoadingForm;


        //////////////////////////////////////////////////////////////////////////
        //axis mesh
        private Mesh m_mAxisCylinder;
        private Mesh m_mAxisArrow;
        private Mesh m_mOrigin;

        //axis labels etc
        private string m_strZLabel = "Label Z";
        private string m_strXLabel = "Label X";
        private string m_strYLabel = "Label Y";
        private Mesh m_ZLabelMesh;
        private Mesh m_XLabelMesh;
        private Mesh m_YLabelMesh;


        private List<Vector3> m_ZMarkerPositions = new List<Vector3>();
        private List<Vector3> m_XMarkerPositions = new List<Vector3>();
        private List<Vector3> m_YMarkerPositions = new List<Vector3>();


        //////////////////////////////////////////////////////////////////////////
        /// COLORS 
        //////////////////////////////////////////////////////////////////////////
        private Color m_ColorBgNormal = Color.FromArgb(255, 40, 40, 40);
        private Color m_ColorBgCurrent = Color.FromArgb(255, 40, 40, 40);
        private Color m_ColorBgPrinter = Color.White;

        private Color m_ColorAxisNormal = Color.Black;
        private Color m_ColorAxisPrinter = Color.Black;
        private Color m_ColorAxisCurrent = Color.Black;

        private Color m_ColorFontNormal = Color.LightGray;
        private Color m_ColorFontPriner = Color.Black;
        private Color m_ColorFontCurrent = Color.LightGray;
        /////////////////////////////////////////////////////////////////////////
        private bool m_bRenderBoundingBox = true;
        private bool m_bIsLoading = false;
        private string m_ErrorText;



        private bool ErrorTextPresent
        {
            get
            {
                return !(m_ErrorText == null || m_ErrorText == "");
            }

        }





        public bool IsLoading
        {
            get { return m_bIsLoading; }
            set
            {
                m_bIsLoading = value;
                Refresh();
            }
        }


        public float CurrentCameraDistance
        {
            get { return m_fCurrentCameraDistance; }
            set
            {
                m_fCurrentCameraDistance = value;
                if (m_fCurrentCameraDistance > m_fMaxCameraDistance)
                    m_fCurrentCameraDistance = m_fMaxCameraDistance;
                else if (m_fCurrentCameraDistance < m_fMinCameraDistance)
                    m_fCurrentCameraDistance = m_fMinCameraDistance;

                SetCamera();
                if (m_PlotData != null && m_PlotData.Settings.PlotProjectionType == ProjectionType.Orthographic)
                    SetProjection();    //
            }
        }




        struct AxisMarker
        {
            public float m_fValue;


            public Mesh m_Text3D;
            public Vector3 m_vPosition;
        }


        private Microsoft.DirectX.Direct3D.Font m_axisFont;

        //bounding box
        private VertexBuffer m_vbPlotArea;
        private IndexBuffer m_ibPlotAreaBBTriangles;
        private IndexBuffer m_ibPlotAreaBBLines;

        private float m_bbAreaScale = 1.05f;




        //////////////////////////////////////////////////////////////////////////
        //Plot data
        InternalScatterplotData m_PlotData;

        public InternalScatterplotData PlotData
        {
            get { return m_PlotData; }
        }
        //////////////////////////////////////////////////////////////////////////
        //Vertex selection

        //private Mesh m_mVertexSelectionMesh;
        //private float m_fSelectionIntensityTreshold = 0.1f;
        private float m_fSelectionSnapDistance = 0.01f;

        private bool m_bVertexSelected = false;
        //private bool m_bDoubleSelection = false;
        //private DataPoint m_SelectedData;
        //private float m_fSelectedIntensity;
        private Vector3 m_vSelectedPosition;
        private Vector3 m_vSelectedData;
        //private bool m_bEnableVertexSelection = true;

        //struct SelectedVertexData
        //{
        //    public Vector3 m_vPosition;
        //    public DataPoint m_DataPoint;
        //    public float m_fRetentionTime;
        //}

        //List<SelectedVertexData> m_SelectedPoints = new List<SelectedVertexData>();

        //////////////////////////////////////////////////////////////////////////
        private Mesh m_mPoint;
        private Texture m_DashedLineTexture;
        private Texture m_WhiteTexture;
        private ContextMenuStrip contextMenuStrip1;
        private IContainer components;
        private ToolStripMenuItem zoomInToolStripMenuItem;
        private ToolStripMenuItem zoomOutToolStripMenuItem;
        private ToolStripSeparator toolStripSeparator1;
        private ToolStripMenuItem saveAsToolStripMenuItem;
        private Material m_mMaterial;


        //////////////////////////////////////////////////////////////////////////
        public Scatterplot3DControl()
            : base()
        {

            InitializeComponent();

            this.MouseDoubleClick += new MouseEventHandler(Scatterplot3DControl_MouseDoubleClick);
        }







        /// <summary>
        /// 
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
            this.zoomInToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            this.zoomOutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
            this.saveAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            this.contextMenuStrip1.SuspendLayout();
            this.SuspendLayout();
            // 
            // contextMenuStrip1
            // 
            this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.zoomInToolStripMenuItem,
            this.zoomOutToolStripMenuItem,
            this.toolStripSeparator1,
            this.saveAsToolStripMenuItem});
            this.contextMenuStrip1.Name = "contextMenuStrip1";
            this.contextMenuStrip1.Size = new System.Drawing.Size(153, 98);
            // 
            // zoomInToolStripMenuItem
            // 
            this.zoomInToolStripMenuItem.Name = "zoomInToolStripMenuItem";
            this.zoomInToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
            this.zoomInToolStripMenuItem.Text = "Zoom In";
            this.zoomInToolStripMenuItem.Click += new System.EventHandler(this.zoomInToolStripMenuItem_Click);
            // 
            // zoomOutToolStripMenuItem
            // 
            this.zoomOutToolStripMenuItem.Name = "zoomOutToolStripMenuItem";
            this.zoomOutToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
            this.zoomOutToolStripMenuItem.Text = "Zoom Out";
            this.zoomOutToolStripMenuItem.Click += new System.EventHandler(this.zoomOutToolStripMenuItem_Click);
            // 
            // toolStripSeparator1
            // 
            this.toolStripSeparator1.Name = "toolStripSeparator1";
            this.toolStripSeparator1.Size = new System.Drawing.Size(149, 6);
            // 
            // saveAsToolStripMenuItem
            // 
            this.saveAsToolStripMenuItem.Name = "saveAsToolStripMenuItem";
            this.saveAsToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
            this.saveAsToolStripMenuItem.Text = "Save As";
            this.saveAsToolStripMenuItem.Click += new System.EventHandler(this.saveAsToolStripMenuItem_Click);
            // 
            // Scatterplot3DControl
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.Name = "Scatterplot3DControl";
            this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Plot3DControl_MouseMove);
            this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Plot3DControl_MouseDown);
            this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.Plot3DControl_MouseUp);
            this.contextMenuStrip1.ResumeLayout(false);
            this.ResumeLayout(false);
            this.ContextMenuStrip = contextMenuStrip1;
            
        }

        #region Utility Methods

        private float CalculateRayPointDistance(Vector3 rayFrom, Vector3 rayDir, Vector3 point, out float distanceToRayFrom)
        {
            distanceToRayFrom = Vector3.Dot(rayDir, point - rayFrom) / rayDir.LengthSq();
            float dist = (point - (rayFrom + distanceToRayFrom * rayDir)).Length();

            return dist;
        }

        private float GetNewRoundNumber(float number, float precision)
        {
            float oldNumber = number;
            number += precision;
            float remainder = number - (int)(number / precision) * precision;
            if (number - remainder == oldNumber)
                return number;
            else
                return number - remainder;
        }

        private float GetRoundNumber(float number, float precision)
        {
            if (number - (int)(number / precision) * precision == 0)
                return number;
            else
                return GetNewRoundNumber(number, precision);
        }

        void BuildAxisLabels()
        {

            //axis label meshes
            if (m_ZLabelMesh != null)
                m_ZLabelMesh.Dispose();
            if (m_XLabelMesh != null)
                m_ZLabelMesh.Dispose();
            if (m_YLabelMesh != null)
                m_YLabelMesh.Dispose();
            if (m_PlotData != null)
                m_strXLabel = m_PlotData.Settings.XLabel;
            else
                m_strXLabel = "Axis X";

            if (m_PlotData != null)
                m_strYLabel = m_PlotData.Settings.YLabel;
            else
                m_strXLabel = "Axis Y";

            if (m_PlotData != null)
                m_strZLabel = m_PlotData.Settings.ZLabel;
            else
                m_strXLabel = "Axis Z";

            m_ZLabelMesh = Mesh.TextFromFont(d3dDevice, this.Font, m_strZLabel, 0.01f, 0.01f);
            m_XLabelMesh = Mesh.TextFromFont(d3dDevice, this.Font, m_strXLabel, 0.01f, 0.01f);
            m_YLabelMesh = Mesh.TextFromFont(d3dDevice, this.Font, m_strYLabel, 0.01f, 0.01f);
        }

        void BuildDashedLine()
        {
            if (m_DashedLineTexture != null && !m_DashedLineTexture.Disposed)
            {
                m_DashedLineTexture.Dispose();
            }

            if (m_WhiteTexture != null && !m_WhiteTexture.Disposed)
            {
                m_WhiteTexture.Dispose();
            }

            Bitmap dashedLineBitmap = null;

            int dashedLineResolution = 256;
            dashedLineBitmap = new Bitmap(dashedLineResolution, 1, PixelFormat.Format32bppArgb);
            BitmapData bmpData = dashedLineBitmap.LockBits(new Rectangle(0, 0, dashedLineResolution, 1), System.Drawing.Imaging.ImageLockMode.WriteOnly,
                 System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            IntPtr ptr = bmpData.Scan0;
            int[] argbData = new int[dashedLineResolution];

            for (int i = 0; i < dashedLineResolution; i++)
            {
                if (i < dashedLineResolution / 2)
                    argbData[i] = Color.FromArgb(255, 90, 90, 90).ToArgb();
                else
                    argbData[i] = Color.FromArgb(0, 0, 0, 0).ToArgb();
            }
            System.Runtime.InteropServices.Marshal.Copy(argbData, 0, ptr, argbData.Length);
            dashedLineBitmap.UnlockBits(bmpData);

            //dashedLineBitmap.Save("dashed.bmp");
            m_DashedLineTexture = new Texture(d3dDevice, dashedLineBitmap, Usage.None, Pool.Managed);

            Bitmap whiteBitmap = null;
            whiteBitmap = new Bitmap(2, 2, PixelFormat.Format32bppArgb);
            bmpData = whiteBitmap.LockBits(new Rectangle(0, 0, 2, 2), System.Drawing.Imaging.ImageLockMode.WriteOnly,
                 System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            ptr = bmpData.Scan0;
            argbData = new int[4];

            for (int i = 0; i < 4; i++)
            {
                argbData[i] = Color.White.ToArgb();
            }
            System.Runtime.InteropServices.Marshal.Copy(argbData, 0, ptr, argbData.Length);
            whiteBitmap.UnlockBits(bmpData);

            //dashedLineBitmap.Save("dashed.bmp");
            m_WhiteTexture = new Texture(d3dDevice, whiteBitmap, Usage.None, Pool.Managed);
        }




        /// <summary>
        /// Current Z axis minimum
        /// </summary>
        float AxisMinZ
        {
            get
            {
                return m_PlotData.MinZ + m_PlotZoom.ZOffset * m_PlotData.ZRange;
            }
        }
        /// <summary>
        /// Current Z axis maximum
        /// </summary>
        float AxisMaxZ
        {
            get
            {
                return m_PlotData.MinZ + (m_PlotZoom.ZOffset + m_PlotZoom.Subset) * m_PlotData.ZRange;
            }
        }

        /// <summary>
        /// Current X axis minimum
        /// </summary>
        float AxisMinX
        {
            get
            {
                return m_PlotData.MinX + m_PlotZoom.XOffset * m_PlotData.XRange;
            }
        }
        /// <summary>
        /// Current X axis maximum
        /// </summary>
        float AxisMaxX
        {
            get
            {
                return m_PlotData.MinX + (m_PlotZoom.XOffset + m_PlotZoom.Subset) * m_PlotData.XRange;
            }
        }

        /// <summary>
        /// Current Y axis minimum
        /// </summary>
        float AxisMinY
        {
            get
            {
                return m_PlotData.MinY + m_PlotZoom.YOffset * m_PlotData.YRange;
            }
        }
        /// <summary>
        /// Current Y axis maximum
        /// </summary>
        float AxisMaxY
        {
            get
            {
                return m_PlotData.MinY + (m_PlotZoom.YOffset + m_PlotZoom.Subset) * m_PlotData.YRange;
            }
        }

        /// <summary>
        /// Converts world(3D) coordinates to screen(2D) coordinates
        /// </summary>
        /// <param name="vPos"></param>
        /// <returns></returns>
        private Vector2 WorldToScreen(Vector3 vPos)
        {
            vPos.Project(d3dDevice.Viewport, m_ProjectionMatrix, m_ViewMatrix, Matrix.Identity);
            Vector2 result;
            result.X = vPos.X;
            result.Y = vPos.Y;
            return result;
        }

        /// <summary>
        /// Converts world(3D) coordinates to screen(2D) coordinates
        /// </summary>
        /// <param name="vPos"></param>
        /// <returns></returns>
        private Vector2 WorldToScreen(Vector3 vPos, Matrix world)
        {
            vPos.Project(d3dDevice.Viewport, m_ProjectionMatrix, m_ViewMatrix, world);
            Vector2 result;
            result.X = vPos.X;
            result.Y = vPos.Y;
            return result;
        }


   

        #endregion

        #region Data methods


        /// <summary>
        /// Sets data for the Plot3D
        /// </summary>
        /// <param name="arrList">Plot data struct filled with samples to plot</param>
        public void SetData(InternalScatterplotData plotData)
        {
            if (d3dDevice == null) return;

            debugLog.Write("Setting new Plot Data");
            m_ErrorText = "";//no error, for now
            if(plotData==null || plotData.PlotData.Count==0)
            {
                m_PlotData = null;
                m_ErrorText = "No plot data";
                Refresh();
                return;
            }
            else
                m_PlotData = plotData;

            IsLoading = true;   //display loading screen
            //m_ColorBgNormal=m_PlotData.Settings.
            SetColorMode(plotData.Settings.PrinterFriendlyColors);
            if (m_PlotData.PlotType == ScatterplotType.Normal)
            {
                m_vPlotArea = new Vector3(100, 70, 100);
                m_vPlotPosition = new Vector3(0, 0, 0);
            }
            else
            {
                m_vPlotArea = new Vector3(100, 100, 100);
                m_vPlotPosition = new Vector3(0, -30, 0);
            }
            
            BuildAxisLabels();
            SetProjection();

            IsLoading = false;
            Refresh();

        }


        /// <summary>
        /// Updates current plot using new settings
        /// </summary>
        /// <param name="newSettings">New plot settings</param>
        public void UpdatePlot(ScatterplotSettings newSettings)
        {
            if (d3dDevice == null) return;
            m_ErrorText = "";

            IsLoading = true;
            

            m_PlotData.Settings = newSettings;
            SetColorMode(newSettings.PrinterFriendlyColors);
            BuildAxisLabels();
            SetProjection();

            IsLoading = false;
            Refresh();

        }
        #endregion


        #region Data selection methods

        private bool SelectVertex(int mouseX, int mouseY, out Vector3 selectedPos, out Vector3 selectedData)
        {

            List<Vector3> selectedPoints = new List<Vector3>();
            List<Vector3> selectedUntransformedPoints = new List<Vector3>();
            for (int i = 0; i < m_PlotData.PlotData.Count; i++)
            {
                float selectionRadius = 5f;
                Vector3 pos = m_PlotData.PlotData[i].Position;
                Vector3 origPos = pos;
                pos.TransformCoordinate(m_PlotTransform);

                Vector2 screenPos = WorldToScreen(pos);
                screenPos.X -= mouseX;
                screenPos.Y -= mouseY;
                if (screenPos.Length() < selectionRadius)
                {
                    selectedPoints.Add(pos);
                    selectedUntransformedPoints.Add(origPos);
                }
            }
            if (selectedPoints.Count > 0)
            {
                float minDist = -1;
                int closestPoint = -1;
                for (int i = 0; i < selectedPoints.Count; i++)
                {
                    if (minDist == -1 || (selectedPoints[i] - m_vCameraPos).Length() < minDist)
                    {
                        minDist = (selectedPoints[i] - m_vCameraPos).Length();
                        closestPoint = i;
                    }
                }

                selectedPos = selectedPoints[closestPoint];
                selectedData = selectedUntransformedPoints[closestPoint];
                return true;

            }
            selectedPos = new Vector3(0, 0, 0);
            selectedData = new Vector3();
            return false;
        }


        #endregion

        #region Device Callbacks

        /// <summary>
        /// Called after a new device is created(only once), things that are in the managed pool should be created here.
        /// </summary>
        /// <param name="obj">Not used</param>
        /// <param name="args">Not used</param>
        protected override void OnCreateDevice(object obj, EventArgs args)
        {
            base.OnCreateDevice(obj, args);
            ResetCamera();



            m_debugFont = new Microsoft.DirectX.Direct3D.Font(d3dDevice, 15, 0, FontWeight.Normal, 1, false, CharacterSet.Default, Precision.Default,
                FontQuality.Default, PitchAndFamily.DefaultPitch | PitchAndFamily.FamilyDoNotCare, "Arial");
            m_axisFont = new Microsoft.DirectX.Direct3D.Font(d3dDevice, 15, 0, FontWeight.Bold, 1, false, CharacterSet.Default, Precision.Default,
                FontQuality.Default, PitchAndFamily.DefaultPitch | PitchAndFamily.FamilyDoNotCare, "Arial");
            m_LoadingFont = new Microsoft.DirectX.Direct3D.Font(d3dDevice, 30, 0, FontWeight.Bold, 1, false, CharacterSet.Default, Precision.Default,
                FontQuality.Default, PitchAndFamily.DefaultPitch | PitchAndFamily.FamilyDoNotCare, "Arial");
            m_PlotTitleFont = new Microsoft.DirectX.Direct3D.Font(d3dDevice, 30, 0, FontWeight.Bold, 1, false, CharacterSet.Default, Precision.Default,
                FontQuality.Default, PitchAndFamily.DefaultPitch | PitchAndFamily.FamilyDoNotCare, "Arial");
            m_PlotSubtitleFont = new Microsoft.DirectX.Direct3D.Font(d3dDevice, 15, 0, FontWeight.Bold, 1, false, CharacterSet.Default, Precision.Default,
                FontQuality.Default, PitchAndFamily.DefaultPitch | PitchAndFamily.FamilyDoNotCare, "Arial");
            m_LegendFont = new Microsoft.DirectX.Direct3D.Font(d3dDevice, 20, 0, FontWeight.Bold, 1, false, CharacterSet.Default, Precision.Default,
                FontQuality.Default, PitchAndFamily.DefaultPitch | PitchAndFamily.FamilyDoNotCare, "Arial");
            
            m_spriteObject = new Sprite(d3dDevice);
            m_mPoint = Mesh.Sphere(d3dDevice, 0.5f, 4, 4);
            this.m_mMaterial = new Material();



            m_SurfaceMaterial = new Material();
            m_SurfaceMaterial.Ambient = Color.DarkGray;
            m_SurfaceMaterial.Diffuse = Color.White;
            //////////////////////////////////////////////////////////////////////////
            //Load axis meshes
            float fAxisThickness = 0.4f;
            m_mAxisArrow = Mesh.Cylinder(d3dDevice, fAxisThickness * 3, 0, 10 * fAxisThickness, 10, 1);
            m_mAxisCylinder = Mesh.Cylinder(d3dDevice, fAxisThickness, fAxisThickness, 1, 10, 1);
            m_mOrigin = Mesh.Sphere(d3dDevice, 2f * fAxisThickness, 10, 10);
            m_PlotPointMesh = Mesh.Sphere(d3dDevice, 1.0f, 10, 10);
            m_PlotSphereMesh = Mesh.Sphere(d3dDevice, 1.0f, 32, 32);

            //create plot bounding box 
            m_ibPlotAreaBBTriangles = new IndexBuffer(typeof(int), 36, d3dDevice, Usage.WriteOnly, Pool.Managed);
            m_ibPlotAreaBBLines = new IndexBuffer(typeof(int), 24, d3dDevice, Usage.WriteOnly, Pool.Managed);

            m_vbPlotArea = new VertexBuffer(typeof(CustomVertex.PositionColored), 8, d3dDevice, Usage.WriteOnly, CustomVertex.PositionColored.Format, Pool.Managed);

            CustomVertex.PositionColored[] vbData = (CustomVertex.PositionColored[])m_vbPlotArea.Lock(0, 0);

            int color = Color.FromArgb(50, 80, 80, 80).ToArgb();

            vbData[0] = new CustomVertex.PositionColored(-1, -1, -1, color);
            vbData[1] = new CustomVertex.PositionColored(1, -1, -1, color);
            vbData[2] = new CustomVertex.PositionColored(1, -1, 1, color);
            vbData[3] = new CustomVertex.PositionColored(-1, -1, 1, color);
            vbData[4] = new CustomVertex.PositionColored(-1, 1, -1, color);
            vbData[5] = new CustomVertex.PositionColored(1, 1, -1, color);
            vbData[6] = new CustomVertex.PositionColored(1, 1, 1, color);
            vbData[7] = new CustomVertex.PositionColored(-1, 1, 1, color);
            m_vbPlotArea.Unlock();

            //selection cube


            int[] triangleIndices ={0,2,1,0,3,2,
                              0,4,3,4,7,3,
                              1,6,5,1,2,6,
                              0,5,4,0,1,5,
                              3,7,6,3,6,2,
                              4,5,6,4,6,7};

            m_ibPlotAreaBBTriangles.SetData(triangleIndices, 0, LockFlags.None);

            int[] lineIndices = { 0, 1, 1, 2, 2, 3, 3, 0, 0, 4, 1, 5, 2, 6, 3, 7, 4, 5, 5, 6, 6, 7, 7, 4 };

            m_ibPlotAreaBBLines.SetData(lineIndices, 0, LockFlags.None);

            //m_tGrayBox = TextureLoader.FromFile(d3dDevice, "Gray.png", 0, 0, 0, Usage.None, Format.A8R8G8B8, Pool.Managed, Filter.Linear, Filter.Linear, 0);



            //m_mVertexSelectionMesh = Mesh.Sphere(d3dDevice, 2, 10, 10);


            BuildAxisLabels();


            BuildDashedLine();



        }

        /// <summary>
        /// Called after device reset(new present parameters) and just after creating the device and calling OnCreateDevice
        /// Everything that isn't in the managed pool should be created here.
        /// </summary>
        /// <param name="obj">Not used</param>
        /// <param name="args">Not used</param>
        protected override void OnResetDevice(object obj, EventArgs args)
        {
            base.OnResetDevice(obj, args);
            SetProjection();
            SetCamera();

           

            d3dDevice.Lights[0].Type = LightType.Directional;
            d3dDevice.Lights[0].Diffuse = Color.White;
            d3dDevice.Lights[0].Ambient = Color.DarkGray;
            d3dDevice.Lights[0].Direction = new Vector3(0f, -0.3f, -1f);
            d3dDevice.Lights[0].Enabled = true;

        }
        /// <summary>
        /// Called after the device has been lost
        /// </summary>
        /// <param name="obj">Not used</param>
        /// <param name="args">Not used</param>
        protected override void OnLostDevice(object obj, EventArgs args)
        {
            base.OnLostDevice(obj, args);
        }

        /// <summary>
        /// Called when the application is exiting and the device is being destroyed. Delete all device objects here
        /// (meshes, vertex buffers etc.)
        /// </summary>
        /// <param name="obj">Not used</param>
        /// <param name="args">Not used</param>
        protected override void OnDestroyDevice(object obj, EventArgs args)
        {
            base.OnDestroyDevice(obj, args);
            //fonts
            m_debugFont.Dispose();
            m_axisFont.Dispose();
            m_LoadingFont.Dispose();
            m_LegendFont.Dispose();
            m_PlotTitleFont.Dispose();
            m_PlotSubtitleFont.Dispose();
            m_spriteObject.Dispose();
            m_mPoint.Dispose();
            m_PlotPointMesh.Dispose();

            //textures
            if (m_WhiteTexture != null)
                m_WhiteTexture.Dispose();

            if (m_DashedLineTexture != null)
                m_DashedLineTexture.Dispose();


            //meshes
            if (m_ZLabelMesh != null)
                m_ZLabelMesh.Dispose();
            if (m_XLabelMesh != null)
                m_ZLabelMesh.Dispose();
            if (m_YLabelMesh != null)
                m_YLabelMesh.Dispose();


        }
        #endregion



        #region Camera Related


        /// <summary>
        /// Resets the camera to default parameters(position, zoom)
        /// </summary>
        public void ResetCamera()
        {
            m_vInitialCameraPos = new Vector3(-10, m_vPlotArea.Y / 2, 2 * m_vPlotArea.Z);
            m_vInitialLookAt = new Vector3(-10, m_vPlotArea.Y / 4, 0);
            m_vCameraPos = m_vInitialCameraPos;
            m_vLookAt = m_vInitialLookAt;
            
            m_fCameraRotationX = 0;
            m_fCameraRotationY = 0;
            CurrentCameraDistance = m_fMaxCameraDistance;
            ResetZoom();

            SetCamera();
            Refresh();
        }

        /// <summary>
        /// Sets correct projection- currently perspective only
        /// </summary>
        void SetProjection()
        {
            if (d3dDevice == null) return;

            if (m_PlotData != null && m_PlotData.Settings.PlotProjectionType == ProjectionType.Orthographic)
            {
                float fAspect = (float)currentPresentParameters.BackBufferWidth / (float)currentPresentParameters.BackBufferHeight;
                float fDesiredAspect = 1.3f;
                if (fAspect < 1.3f)
                {
                    float fOrthoSize = 2 * m_fCurrentCameraDistance * (float)Math.Tan(Math.PI / 8);
                    m_ProjectionMatrix = Matrix.OrthoRH(fOrthoSize, fOrthoSize / fAspect, 0.1f, 1000f);
                }
                else
                {
                    float fOrthoSize = 2 * m_fCurrentCameraDistance * (float)Math.Tan(Math.PI / 8);
                    m_ProjectionMatrix = Matrix.OrthoRH(fAspect * fOrthoSize / fDesiredAspect, fOrthoSize / fDesiredAspect, 0.1f, 1000f);
                }
            }
            else
            {
                m_ProjectionMatrix = Matrix.PerspectiveFovRH((float)Math.PI / 4, (float)currentPresentParameters.BackBufferWidth / (float)currentPresentParameters.BackBufferHeight, 0.5f, 500.0f);
            }
            d3dDevice.Transform.Projection = m_ProjectionMatrix;

            d3dDevice.Transform.World = Matrix.Identity;
            //d3dDevice.Transform.View = Matrix.LookAtRH(new Vector3(0, 0, 200), new Vector3(0, 0, 0), new Vector3(0, 1, 0));

            d3dDevice.Transform.View = Matrix.LookAtRH(m_vCameraPos, m_vLookAt, new Vector3(0, 1, 0));
        }

        /// <summary>
        /// Builds and sets a view matrix based on current camera settings
        /// </summary>
        void SetCamera()
        {
            if (d3dDevice == null) return;
            m_vCameraPos = m_vInitialCameraPos - m_vInitialLookAt;

            m_vCameraPos.TransformNormal(Matrix.RotationX(m_fCameraRotationX));
            m_vCameraPos.TransformNormal(Matrix.RotationY(m_fCameraRotationY));
            m_vCameraPos *= m_fCurrentCameraDistance / m_vCameraPos.Length();
            m_vCameraPos += m_vInitialLookAt;
            m_ViewMatrix = Matrix.LookAtRH(m_vCameraPos, m_vLookAt, new Vector3(0, 1, 0));



            d3dDevice.Transform.View = m_ViewMatrix;
        }


        #endregion


        #region Rendering methods

        private void SetColorMode(bool printerFriendly)
        {
            if (printerFriendly)
            {
                m_ColorBgCurrent = m_ColorBgPrinter;
                m_ColorFontCurrent = m_ColorFontPriner;
                m_ColorAxisCurrent = m_ColorAxisPrinter;
                m_ColorBgCurrent = m_ColorBgPrinter;
                m_bRenderBoundingBox = false;
            }
            else
            {
                m_ColorBgCurrent = m_ColorBgNormal;
                m_ColorFontCurrent = m_ColorFontNormal;
                m_ColorAxisCurrent = m_ColorAxisNormal;
                m_ColorBgCurrent = m_PlotData.Settings.BackgroundColor;
                m_bRenderBoundingBox = true;
            }
        }
        /// <summary>
        /// Renders the plot to a bitmap
        /// </summary>
        /// <param name="bitmapWidth">Bitmap width in pixels</param>
        /// <param name="bitmapHeight">Bitmap height in pixels</param>
        /// <param name="printerColors">If this is true then a white background is used with black text</param>
        /// <returns>Bitmap containing the plot</returns>
        public Bitmap RenderToBitmap(int bitmapWidth, int bitmapHeight, bool printerColors)
        {
            if (d3dDevice == null) return null;
            try
            {
                bool oldPrinterColors = m_PlotData.Settings.PrinterFriendlyColors;
                SetColorMode(printerColors);
                RenderToSurface rtsHelper = new RenderToSurface(d3dDevice, bitmapWidth, bitmapHeight, Format.A8R8G8B8, true, DepthFormat.D16);
                Texture renderTexture = new Texture(d3dDevice, bitmapWidth, bitmapHeight, 1, Usage.RenderTarget, Format.A8R8G8B8, Pool.Default);
                Surface renderSurface = renderTexture.GetSurfaceLevel(0);
                Surface old = d3dDevice.GetRenderTarget(0);
                rtsHelper.BeginScene(renderSurface);
                RenderControl();
                rtsHelper.EndScene(Filter.None);

                SetColorMode(oldPrinterColors);
                GraphicsStream img_stream = TextureLoader.SaveToStream(ImageFileFormat.Png, renderTexture);
                Bitmap bmp = new Bitmap(Bitmap.FromStream(img_stream));
                //bmp.Save("o.png");
                return bmp;
            }
            catch (System.Exception e)
            {
                m_ColorBgCurrent = m_ColorBgNormal;
                MessageBox.Show(e.Message);
            }
            return null;

        }
        /// <summary>
        /// Renders control
        /// </summary>
        protected override void RenderControl()
        {
            if (d3dDevice == null ) return;

            m_iFrameNumber++;

            d3dDevice.Clear(ClearFlags.Target | ClearFlags.ZBuffer, m_ColorBgCurrent, 1, 0);
            if (ErrorTextPresent)
            {
                RenderErrorText();
                return;
            }

            if (m_PlotData != null && m_PlotData.Settings.Title != "" && m_PlotData.Settings.Title != null)
            {
                m_PlotTitleFont.DrawText(null, m_PlotData.Settings.Title,new Rectangle(0,10,currentPresentParameters.BackBufferWidth,30),DrawTextFormat.Center, m_ColorFontCurrent);
            }
            if (m_PlotData != null && m_PlotData.Settings.Subtitle != "" && m_PlotData.Settings.Subtitle != null)
            {
                m_PlotSubtitleFont.DrawText(null, m_PlotData.Settings.Subtitle, new Rectangle(0, 40, currentPresentParameters.BackBufferWidth, 30), DrawTextFormat.Center, m_ColorFontCurrent);

                m_axisFont.DrawText(null, "(Correlation Threshold=" + m_PlotData.Settings.CorrelationThreshold.ToString("F01") + ")", new Rectangle(0, 55, currentPresentParameters.BackBufferWidth, 30), DrawTextFormat.Center, m_ColorFontCurrent);
            }
            else if (m_PlotData != null && m_PlotData.PlotType== ScatterplotType.BiPlot)
            {
                m_axisFont.DrawText(null, "(Correlation Threshold="+m_PlotData.Settings.CorrelationThreshold.ToString("F01")+")", new Rectangle(0,40, currentPresentParameters.BackBufferWidth, 30), DrawTextFormat.Center, m_ColorFontCurrent);
            }

            //RenderLineAxes();
            RenderAxisMarkers();
            d3dDevice.Clear(ClearFlags.ZBuffer, Color.Black, 1, 0);
            RenderSolidAxes();
            RenderSolidAxisNames();
            //RenderIntensityMarkers();
            RenderGrid();
            RenderSolidAxes();

            RenderPlot();


            // RenderSelectionBalls();

            if (m_PlotData == null) return;
            if(m_PlotData.PlotType== ScatterplotType.Normal ||! m_PlotData.Settings.DrawInnerPlanes)
            {
                RenderBoundingBox();
            }
            else
            {
                RenderInnerPlanes();
            }


            RenderLegend();
            RenderDebugText();

            if (m_bIsLoading)
                RenderLoadingScreen();

        }

        /// <summary>
        /// Renders all 3 axes using simple lines
        /// </summary>
        void RenderLineAxes()
        {
            d3dDevice.VertexFormat = CustomVertex.PositionColored.Format;
            d3dDevice.Transform.World = Matrix.Identity;
            //axis color-black
            Color black = Color.Black;

            CustomVertex.PositionColored[] vertices = new CustomVertex.PositionColored[6];

            vertices[0].Color = Color.Black.ToArgb();
            vertices[0].Position = new Vector3(m_vPlotPosition.X - m_vPlotArea.X / 2, m_vPlotPosition.Y, m_vPlotPosition.Z + m_vPlotArea.Z / 2);

            vertices[1].Color = Color.Black.ToArgb();
            vertices[1].Position = new Vector3(m_vPlotPosition.X + m_vPlotArea.X / 2, m_vPlotPosition.Y, m_vPlotPosition.Z + m_vPlotArea.Z / 2);

            vertices[2].Color = Color.Black.ToArgb();
            vertices[2].Position = new Vector3(m_vPlotPosition.X - m_vPlotArea.X / 2, m_vPlotPosition.Y, m_vPlotPosition.Z + m_vPlotArea.Z / 2);

            vertices[3].Color = Color.Black.ToArgb();
            vertices[3].Position = new Vector3(m_vPlotPosition.X - m_vPlotArea.X / 2, m_vPlotPosition.Y, m_vPlotPosition.Z - m_vPlotArea.Z / 2);

            vertices[4].Color = Color.Black.ToArgb();
            vertices[4].Position = new Vector3(m_vPlotPosition.X - m_vPlotArea.X / 2, m_vPlotPosition.Y, m_vPlotPosition.Z + m_vPlotArea.Z / 2);

            vertices[5].Color = Color.Black.ToArgb();
            vertices[5].Position = new Vector3(m_vPlotPosition.X - m_vPlotArea.X / 2, m_vPlotPosition.Y + m_vPlotArea.Y, m_vPlotPosition.Z + m_vPlotArea.Z / 2);




            d3dDevice.DrawUserPrimitives(PrimitiveType.LineList, 3, vertices);
        }

        /// <summary>
        /// Renders all 3 axes using 3D graphics
        /// </summary>
        void RenderSolidAxes()
        {
            d3dDevice.VertexFormat = CustomVertex.PositionColored.Format;
            d3dDevice.Transform.World = Matrix.Identity;
            //axis color-black
            Color black = Color.Black;
            d3dDevice.RenderState.Lighting = false;


            float fAxisOffset = 3.1f;

            float fArrowOffset = 9.9f;

            d3dDevice.RenderState.Lighting = true;
            Material mat = new Material();
            mat.Ambient = m_ColorAxisCurrent;
            d3dDevice.Material = mat;
            Vector3 vbbPlotArea = m_vPlotArea * m_bbAreaScale * 0.99f;

            Vector3 vAxisOffset = new Vector3(-fAxisOffset, -fAxisOffset - 0.2f, fAxisOffset);
            //origin
            Matrix mOrigin = Matrix.Translation(m_vPlotPosition - (new Vector3(vbbPlotArea.X + 6, 7.5f, -vbbPlotArea.Z - 6) * 0.5f));
            d3dDevice.Transform.World = mOrigin;

            m_mOrigin.DrawSubset(0);

            //x axis
            d3dDevice.Transform.World = Matrix.Scaling(1, 1, vbbPlotArea.X + fArrowOffset) * Matrix.RotationY(-(float)Math.PI / 2) * Matrix.Translation(m_vPlotPosition + new Vector3(10, -1, vbbPlotArea.Z) * 0.5f + vAxisOffset);
            m_mAxisCylinder.DrawSubset(0);

            d3dDevice.Transform.World = Matrix.RotationY((float)Math.PI / 2) * Matrix.Translation(m_vPlotPosition + new Vector3(vbbPlotArea.X + 7 + 1.5f * fArrowOffset, -1, vbbPlotArea.Z) * 0.5f + vAxisOffset);
            m_mAxisArrow.DrawSubset(0);

            //y axis
            d3dDevice.Transform.World = Matrix.Scaling(1, 1, vbbPlotArea.Y + fArrowOffset) * Matrix.RotationX(-(float)Math.PI / 2) * Matrix.Translation(m_vPlotPosition + new Vector3(-vbbPlotArea.X, vbbPlotArea.Y + 8, vbbPlotArea.Z) * 0.5f + vAxisOffset);
            m_mAxisCylinder.DrawSubset(0);

            d3dDevice.Transform.World = Matrix.RotationX(-(float)Math.PI / 2) * Matrix.Translation(m_vPlotPosition + new Vector3(-vbbPlotArea.X, 2 * vbbPlotArea.Y + 3 + 1.5f * fArrowOffset, vbbPlotArea.Z) * 0.5f + vAxisOffset);
            m_mAxisArrow.DrawSubset(0);

            //z axis
            d3dDevice.Transform.World = Matrix.Scaling(1, 1, vbbPlotArea.Z + fArrowOffset) * Matrix.Translation(m_vPlotPosition + new Vector3(-vbbPlotArea.X, -1, -10) * 0.5f + vAxisOffset);
            m_mAxisCylinder.DrawSubset(0);

            d3dDevice.Transform.World = Matrix.RotationY((float)Math.PI) * Matrix.Translation(m_vPlotPosition + new Vector3(-vbbPlotArea.X, -1, -vbbPlotArea.Z - 7 - 1.5f * fArrowOffset) * 0.5f + vAxisOffset);
            m_mAxisArrow.DrawSubset(0);

        }

        /// <summary>
        /// Renders axis labels using 3D text
        /// </summary>
        void RenderSolidAxisNames()
        {
            d3dDevice.Transform.World = Matrix.Identity;
            //axis color-black
            Color black = Color.Black;
            d3dDevice.RenderState.Lighting = false;


            float fAxisOffset = 0.3f;


            d3dDevice.RenderState.Lighting = true;
            Material mat = new Material();
            mat.Ambient = m_ColorAxisCurrent;
            d3dDevice.Material = mat;

            Vector3 vAxisOffset = new Vector3(-fAxisOffset, -fAxisOffset, fAxisOffset);
            //origin
            Matrix mOrigin = Matrix.Translation(m_vPlotPosition - (new Vector3(m_vPlotArea.X, 0, -m_vPlotArea.Z) * 0.5f) + vAxisOffset);


            //x axis


            d3dDevice.Transform.World = Matrix.Scaling(8.5f, 8.5f, 8.5f) * Matrix.RotationX(-0.9f) * Matrix.Translation(m_vPlotPosition + new Vector3(-45, -30, m_vPlotArea.Z + 46) * 0.5f);
            m_XLabelMesh.DrawSubset(0);

            ////y axis
            if (m_fCameraRotationY > 1.75 * Math.PI || m_fCameraRotationY < 0.75 * Math.PI)
            {
                d3dDevice.Transform.World = Matrix.Scaling(8.5f, 8.5f, 8.5f) * Matrix.RotationZ(1.57079f) * Matrix.RotationY(0.75f) * Matrix.Translation(m_vPlotPosition + new Vector3(-35 - m_vPlotArea.X, m_vPlotArea.Y - 34, m_vPlotArea.Z + 35) * 0.5f);
                m_YLabelMesh.DrawSubset(0);//
            }
            else
            {
                d3dDevice.Transform.World = Matrix.Scaling(8.5f, 8.5f, 8.5f) * Matrix.RotationZ(1.57079f) * Matrix.RotationY((float)Math.PI + 0.75f) * Matrix.Translation(m_vPlotPosition + new Vector3(-35 - m_vPlotArea.X, m_vPlotArea.Y - 34, m_vPlotArea.Z + 35) * 0.5f);
                m_YLabelMesh.DrawSubset(0);//
            }


            //z axis
            d3dDevice.Transform.World = Matrix.Scaling(8.5f, 8.5f, 8.5f) * Matrix.RotationY(-1.57079f) * Matrix.RotationZ(-0.9f) * Matrix.Translation(m_vPlotPosition + new Vector3(-46 - m_vPlotArea.X, -30, -35) * 0.5f);
            m_ZLabelMesh.DrawSubset(0);



        }

        /// <summary>
        /// Renders a dashed line between 2 points
        /// </summary>
        /// <param name="from"></param>
        /// <param name="to"></param>
        void RenderDashedLine(Vector3 from, Vector3 to)
        {
            CustomVertex.PositionTextured[] vertices = new CustomVertex.PositionTextured[2];
            vertices[0] = new CustomVertex.PositionTextured(from, 0, 0);
            vertices[1] = new CustomVertex.PositionTextured(to, (int)((from - to).Length() / 5.0f) + 0.5f, 0);

            d3dDevice.VertexFormat = CustomVertex.PositionTextured.Format;
            d3dDevice.SetTexture(0, m_DashedLineTexture);
            d3dDevice.DrawUserPrimitives(PrimitiveType.LineList, 1, vertices);
            d3dDevice.SetTexture(0, null);
        }

        /// <summary>
        /// Renders intensity markers and text labels
        /// </summary>
        void RenderIntensityMarkers()
        {
            //if (m_PlotData == null) return;
            //if (m_vbPlotVertices == null) return;

            //d3dDevice.Transform.World = Matrix.Identity;
            //d3dDevice.VertexFormat = CustomVertex.PositionColored.Format;
            //d3dDevice.DrawUserPrimitives(PrimitiveType.LineList, m_NumIntensityMarkers, m_IntensityMarkerPoints);

            //for (int i = 0; i < m_NumIntensityMarkers; i++)
            //{
            //    Vector2 vPos = WorldToScreen(m_IntensityMarkers[i].m_vPosition);
            //    m_axisFont.DrawText(null, m_IntensityMarkers[i].m_fValue.ToString("F01"), new Point((int)vPos.X, (int)vPos.Y), m_ColorFontCurrent);
            //}
        }

        /// <summary>
        /// Renders MZ and RT markers and text labels
        /// </summary>
        void RenderAxisMarkers()
        {
            if (m_PlotData == null) return;
            if (m_PlotData.PlotType == ScatterplotType.BiPlot)
            {
                RenderAxisMarkersBiPlot();
                return;
            }
            //if (m_vbPlotVertices == null) return;
            d3dDevice.RenderState.Lighting = false;
            d3dDevice.VertexFormat = CustomVertex.PositionColored.Format;
            d3dDevice.Transform.World = Matrix.Identity;
            ////axis color-black




            int[] aDivisionSteps = new int[] { 1, 2, 5, 10, 25, 50, 100, 200 };
            int orderOfmagnitude = (int)Math.Log10(AxisMaxX - AxisMinX) - 2;
            float multiplier = (float)Math.Pow(10, orderOfmagnitude);

            int currentStep = aDivisionSteps.Length - 1;
            while (currentStep >= 0 && (AxisMaxX - AxisMinX) / (multiplier * aDivisionSteps[currentStep]) < 4)
            {
                currentStep--;
            }

            float rtLabelWidth = 8 * ((int)Math.Log10(AxisMaxX) + 1);
            float labelHeight = 10;
            float rtXOffset = -rtLabelWidth / 2.0f * (1 + (float)Math.Sin(m_fCameraRotationY));
            float rtYOffset = -labelHeight / 2.0f * (float)Math.Sin(m_fCameraRotationY);

            //rt axis
            m_XMarkerPositions.Clear();
            CustomVertex.PositionColored[] vertices = new CustomVertex.PositionColored[2];
            float rt = AxisMinX;
            rt = GetRoundNumber(rt, aDivisionSteps[currentStep] * multiplier);
            for (; rt < AxisMaxX; rt = GetNewRoundNumber(rt, aDivisionSteps[currentStep] * multiplier))
            {
                float pos = (rt - AxisMinX) / (m_PlotZoom.Subset * m_PlotData.XRange);
                Vector3 markerPos = m_vPlotPosition - new Vector3(m_vPlotArea.X, 8, -m_vPlotArea.Z - 9) * (0.5f);
                markerPos.X += pos * m_vPlotArea.X;
                m_XMarkerPositions.Add(markerPos);//save marker position

                Vector3 secondPoint = markerPos + new Vector3(0, -1.5f, 4);
                vertices[0].Position = markerPos;
                vertices[0].Color = Color.Black.ToArgb();

                vertices[1].Position = secondPoint;
                vertices[1].Color = Color.Black.ToArgb();

                d3dDevice.DrawUserPrimitives(PrimitiveType.LineList, 1, vertices);

                secondPoint.Z += 2;

                Vector2 vPos = WorldToScreen(secondPoint);

                m_axisFont.DrawText(null, rt.ToString("F01"), new Point((int)(vPos.X + rtXOffset), (int)(vPos.Y + rtYOffset)), m_ColorFontCurrent);

            }

            //mz axis
            m_ZMarkerPositions.Clear();
            orderOfmagnitude = (int)Math.Log10(AxisMaxZ - AxisMinZ) - 2;
            multiplier = (float)Math.Pow(10, orderOfmagnitude);

            currentStep = aDivisionSteps.Length - 1;
            while (currentStep >= 0 && (AxisMaxZ - AxisMinZ) / (multiplier * aDivisionSteps[currentStep]) < 4)
            {
                currentStep--;
            }
            float mzLabelWidth = 8 * ((int)Math.Log10(AxisMaxZ) + 1);
            //float labelHeight = 10;
            float mzXOffset = -mzLabelWidth / 2.0f * (1 + (float)Math.Cos(m_fCameraRotationY));
            float mzYOffset = -labelHeight / 2.0f * (float)Math.Cos(m_fCameraRotationY);
            //float mzDivider=


            float mz = AxisMinZ;
            mz = GetRoundNumber(mz, multiplier * aDivisionSteps[currentStep]);
            for (; mz < AxisMaxZ; mz = GetNewRoundNumber(mz, multiplier * aDivisionSteps[currentStep]))
            {
                float pos = (mz - AxisMinZ) / (m_PlotZoom.Subset * m_PlotData.ZRange);
                Vector3 markerPos = m_vPlotPosition - new Vector3(m_vPlotArea.X + 9, 8, -m_vPlotArea.Z) * (0.5f);
                markerPos.Z -= pos * m_vPlotArea.Z;
                m_ZMarkerPositions.Add(markerPos); //save marker position
                Vector3 secondPoint = markerPos + new Vector3(-4, -1.5f, 0);
                vertices[0].Position = markerPos;
                vertices[0].Color = Color.Black.ToArgb();

                vertices[1].Position = secondPoint;
                vertices[1].Color = Color.Black.ToArgb();

                d3dDevice.DrawUserPrimitives(PrimitiveType.LineList, 1, vertices);

                secondPoint.X -= 2;
                Vector2 vPos = WorldToScreen(secondPoint);
                m_axisFont.DrawText(null, mz.ToString("F01"), new Point((int)(vPos.X + mzXOffset), (int)(vPos.Y + mzYOffset)), m_ColorFontCurrent);
            }


            //y axis
            m_YMarkerPositions.Clear();
            orderOfmagnitude = (int)Math.Log10(m_PlotZoom.Subset * m_PlotData.YRange) - 2;
            multiplier = (float)Math.Pow(10, orderOfmagnitude);

            currentStep = aDivisionSteps.Length - 1;
            while (currentStep >= 0 && (m_PlotZoom.Subset * m_PlotData.YRange) / (multiplier * aDivisionSteps[currentStep]) < 4)
            {
                currentStep--;
            }
            float yLabelWidth = 8 * ((int)Math.Log10(AxisMaxY) + 1);
            //float labelHeight = 10;
            float yXOffset = -yLabelWidth / 2.0f * (1 + (float)Math.Cos(m_fCameraRotationY));
            float yYOffset = -labelHeight / 2.0f * (float)Math.Cos(m_fCameraRotationY);



            float y = AxisMinY;
            y = GetRoundNumber(y, multiplier * aDivisionSteps[currentStep]);
            for (; y < AxisMaxY; y = GetNewRoundNumber(y, multiplier * aDivisionSteps[currentStep]))
            {
                float pos = (y - AxisMinY) / (m_PlotZoom.Subset * m_PlotData.YRange);
                Vector3 markerPos = m_vPlotPosition - new Vector3(m_vPlotArea.X + 10, 0, -m_vPlotArea.Z - 10) * (0.5f);
                markerPos.Y += pos * m_vPlotArea.Y;
                m_YMarkerPositions.Add(markerPos); //save marker position
                Vector3 secondPoint = markerPos + new Vector3(-4, 0, 4);
                vertices[0].Position = markerPos;
                vertices[0].Color = Color.Black.ToArgb();

                vertices[1].Position = secondPoint;
                vertices[1].Color = Color.Black.ToArgb();

                d3dDevice.DrawUserPrimitives(PrimitiveType.LineList, 1, vertices);

                secondPoint.X -= 2;
                Vector2 vPos = WorldToScreen(secondPoint);
                m_axisFont.DrawText(null, y.ToString("F01"), new Point((int)(vPos.X + yXOffset), (int)(vPos.Y + yYOffset)), m_ColorFontCurrent);

            }
        }

        private void RenderAxisMarkersBiPlot()
        {
            d3dDevice.RenderState.Lighting = false;
            d3dDevice.VertexFormat = CustomVertex.PositionColored.Format;
            d3dDevice.Transform.World = Matrix.Identity;
            ////axis color-black




            int[] aDivisionSteps = new int[] { 1, 2, 5, 10, 25, 50, 100, 200 };
            int orderOfmagnitude = (int)Math.Log10(2.0f) - 2;
            float multiplier = (float)Math.Pow(10, orderOfmagnitude);

            int currentStep = aDivisionSteps.Length - 1;
            while (currentStep >= 0 && (1.0f - -1.0f) / (multiplier * aDivisionSteps[currentStep]) < 4)
            {
                currentStep--;
            }

            float rtLabelWidth = 8 * ((int)Math.Log10(1.0f) + 1);
            float labelHeight = 10;
            float rtXOffset = -rtLabelWidth / 2.0f * (1 + (float)Math.Sin(m_fCameraRotationY));
            float rtYOffset = -labelHeight / 2.0f * (float)Math.Sin(m_fCameraRotationY);

            //rt axis
            m_XMarkerPositions.Clear();
            CustomVertex.PositionColored[] vertices = new CustomVertex.PositionColored[2];
            float rt = -1.0f;
            rt = GetRoundNumber(rt, aDivisionSteps[currentStep] * multiplier);
            for (; rt <= 1.0f; rt = GetNewRoundNumber(rt, aDivisionSteps[currentStep] * multiplier))
            {
                float pos = (rt - -1.0f) / (m_PlotZoom.Subset * 2.0f);
                Vector3 markerPos = m_vPlotPosition - new Vector3(m_vPlotArea.X, 8, -m_vPlotArea.Z - 9) * (0.5f);
                markerPos.X += pos * m_vPlotArea.X;
                m_XMarkerPositions.Add(markerPos);//save marker position

                Vector3 secondPoint = markerPos + new Vector3(0, -1.5f, 4);
                vertices[0].Position = markerPos;
                vertices[0].Color = Color.Black.ToArgb();

                vertices[1].Position = secondPoint;
                vertices[1].Color = Color.Black.ToArgb();

                d3dDevice.DrawUserPrimitives(PrimitiveType.LineList, 1, vertices);

                secondPoint.Z += 2;

                Vector2 vPos = WorldToScreen(secondPoint);

                m_axisFont.DrawText(null, rt.ToString("F01"), new Point((int)(vPos.X + rtXOffset), (int)(vPos.Y + rtYOffset)), m_ColorFontCurrent);

            }

            //mz axis
            m_ZMarkerPositions.Clear();
            orderOfmagnitude = (int)Math.Log10(1.0f - -1.0f) - 2;
            multiplier = (float)Math.Pow(10, orderOfmagnitude);

            currentStep = aDivisionSteps.Length - 1;
            while (currentStep >= 0 && (1.0f - -1.0f) / (multiplier * aDivisionSteps[currentStep]) < 4)
            {
                currentStep--;
            }
            float mzLabelWidth = 8 * ((int)Math.Log10(1.0f) + 1);
            //float labelHeight = 10;
            float mzXOffset = -mzLabelWidth / 2.0f * (1 + (float)Math.Cos(m_fCameraRotationY));
            float mzYOffset = -labelHeight / 2.0f * (float)Math.Cos(m_fCameraRotationY);
            //float mzDivider=


            float mz = -1.0f;
            mz = GetRoundNumber(mz, multiplier * aDivisionSteps[currentStep]);
            for (; mz <= 1.0f; mz = GetNewRoundNumber(mz, multiplier * aDivisionSteps[currentStep]))
            {
                float pos = (mz - -1.0f) / (m_PlotZoom.Subset * 2.0f);
                Vector3 markerPos = m_vPlotPosition - new Vector3(m_vPlotArea.X + 9, 8, -m_vPlotArea.Z) * (0.5f);
                markerPos.Z -= pos * m_vPlotArea.Z;
                m_ZMarkerPositions.Add(markerPos); //save marker position
                Vector3 secondPoint = markerPos + new Vector3(-4, -1.5f, 0);
                vertices[0].Position = markerPos;
                vertices[0].Color = Color.Black.ToArgb();

                vertices[1].Position = secondPoint;
                vertices[1].Color = Color.Black.ToArgb();

                d3dDevice.DrawUserPrimitives(PrimitiveType.LineList, 1, vertices);

                secondPoint.X -= 2;
                Vector2 vPos = WorldToScreen(secondPoint);
                m_axisFont.DrawText(null, mz.ToString("F01"), new Point((int)(vPos.X + mzXOffset), (int)(vPos.Y + mzYOffset)), m_ColorFontCurrent);
            }


            //y axis
            m_YMarkerPositions.Clear();
            orderOfmagnitude = (int)Math.Log10(m_PlotZoom.Subset * 2.0f) - 2;
            multiplier = (float)Math.Pow(10, orderOfmagnitude);

            currentStep = aDivisionSteps.Length - 1;
            while (currentStep >= 0 && (m_PlotZoom.Subset * 2.0f) / (multiplier * aDivisionSteps[currentStep]) < 4)
            {
                currentStep--;
            }
            float yLabelWidth = 8 * ((int)Math.Log10(1.0f) + 1);
            //float labelHeight = 10;
            float yXOffset = -yLabelWidth / 2.0f * (1 + (float)Math.Cos(m_fCameraRotationY));
            float yYOffset = -labelHeight / 2.0f * (float)Math.Cos(m_fCameraRotationY);



            float y = -1.0f;
            y = GetRoundNumber(y, multiplier * aDivisionSteps[currentStep]);
            for (; y <= 1.0f; y = GetNewRoundNumber(y, multiplier * aDivisionSteps[currentStep]))
            {
                float pos = (y - -1.0f) / (m_PlotZoom.Subset * 2.0f);
                Vector3 markerPos = m_vPlotPosition - new Vector3(m_vPlotArea.X + 10, 0, -m_vPlotArea.Z - 10) * (0.5f);
                markerPos.Y += pos * m_vPlotArea.Y;
                m_YMarkerPositions.Add(markerPos); //save marker position
                Vector3 secondPoint = markerPos + new Vector3(-4, 0, 4);
                vertices[0].Position = markerPos;
                vertices[0].Color = Color.Black.ToArgb();

                vertices[1].Position = secondPoint;
                vertices[1].Color = Color.Black.ToArgb();

                d3dDevice.DrawUserPrimitives(PrimitiveType.LineList, 1, vertices);

                secondPoint.X -= 2;
                Vector2 vPos = WorldToScreen(secondPoint);
                m_axisFont.DrawText(null, y.ToString("F01"), new Point((int)(vPos.X + yXOffset), (int)(vPos.Y + yYOffset)), m_ColorFontCurrent);

            }
        }


        void RenderInnerPlanes()
        {
            d3dDevice.RenderState.Lighting = false;

            d3dDevice.RenderState.SourceBlend = Blend.SourceAlpha;
            d3dDevice.RenderState.DestinationBlend = Blend.InvSourceAlpha;


            d3dDevice.Transform.World = Matrix.Scaling(m_vPlotArea * (0.5f + m_bbAreaScale - 1.0f)) *
                Matrix.Translation(m_vPlotPosition.X, m_vPlotPosition.Y + m_vPlotArea.Y / 2, m_vPlotPosition.Z);

            d3dDevice.VertexFormat = CustomVertex.PositionColored.Format;
            d3dDevice.SetStreamSource(0, m_vbPlotArea, 0);
            d3dDevice.Indices = m_ibPlotAreaBBLines;
            //d3dDevice.RenderState.AntiAliasedLineEnable = true;
            //d3dDevice.DrawIndexedPrimitives(PrimitiveType.LineList, 0, 0, 8, 0, 12);

            d3dDevice.Transform.World = Matrix.Scaling(m_vPlotArea * (0.5f + m_bbAreaScale - 1.0f)) *
                Matrix.Translation(m_vPlotPosition.X, m_vPlotPosition.Y + m_vPlotArea.Y / 2 + m_vPlotArea.Y * (0.5f + m_bbAreaScale - 1.0f), m_vPlotPosition.Z);

            d3dDevice.DrawIndexedPrimitives(PrimitiveType.LineList, 0, 0, 8, 0, 4);

            d3dDevice.Transform.World = Matrix.RotationX((float)Math.PI / 2) * Matrix.Scaling(m_vPlotArea * (0.5f + m_bbAreaScale - 1.0f)) *
                            Matrix.Translation(m_vPlotPosition.X, m_vPlotPosition.Y + m_vPlotArea.Y / 2, m_vPlotPosition.Z + m_vPlotArea.Z * (0.5f + m_bbAreaScale - 1.0f));

            d3dDevice.DrawIndexedPrimitives(PrimitiveType.LineList, 0, 0, 8, 0, 4);

            d3dDevice.Transform.World = Matrix.RotationZ((float)Math.PI / 2) * Matrix.Scaling(m_vPlotArea * (0.5f + m_bbAreaScale - 1.0f)) *
                            Matrix.Translation(m_vPlotPosition.X - m_vPlotArea.X * (0.5f + m_bbAreaScale - 1.0f), m_vPlotPosition.Y + m_vPlotArea.Y / 2, m_vPlotPosition.Z);

            d3dDevice.DrawIndexedPrimitives(PrimitiveType.LineList, 0, 0, 8, 0, 4);

            //d3dDevice.RenderState.AntiAliasedLineEnable = false;

            if (!m_bRenderBoundingBox)
                return;


            d3dDevice.RenderState.AlphaBlendEnable = true;
            d3dDevice.RenderState.CullMode = Cull.None;
            d3dDevice.VertexFormat = CustomVertex.PositionColored.Format;
            d3dDevice.Indices = m_ibPlotAreaBBTriangles;

            d3dDevice.Transform.World = Matrix.Scaling(m_vPlotArea * (0.5f + m_bbAreaScale - 1.0f)) *
                Matrix.Translation(m_vPlotPosition.X, m_vPlotPosition.Y + m_vPlotArea.Y / 2 + m_vPlotArea.Y * (0.5f + m_bbAreaScale - 1.0f), m_vPlotPosition.Z);

            d3dDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 8, 0, 2);

            d3dDevice.Transform.World = Matrix.RotationX((float)Math.PI/2 )* Matrix.Scaling(m_vPlotArea * (0.5f + m_bbAreaScale - 1.0f)) *
                            Matrix.Translation(m_vPlotPosition.X, m_vPlotPosition.Y + m_vPlotArea.Y / 2, m_vPlotPosition.Z + m_vPlotArea.Z * (0.5f + m_bbAreaScale - 1.0f));

            d3dDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 8, 0, 2);

            d3dDevice.Transform.World = Matrix.RotationZ((float)Math.PI / 2) * Matrix.Scaling(m_vPlotArea * (0.5f + m_bbAreaScale - 1.0f)) *
                            Matrix.Translation(m_vPlotPosition.X - m_vPlotArea.X * (0.5f + m_bbAreaScale - 1.0f), m_vPlotPosition.Y + m_vPlotArea.Y / 2, m_vPlotPosition.Z );

            d3dDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 8, 0, 2);

            d3dDevice.RenderState.AlphaBlendEnable = false;
            //d3dDevice.RenderState.ZBufferWriteEnable = true;

        }

        /// <summary>
        /// Renders a semi-transparent box, encapsulating the plot
        /// </summary>
        void RenderBoundingBox()
        {

            d3dDevice.RenderState.Lighting = false;

            d3dDevice.RenderState.SourceBlend = Blend.SourceAlpha;
            d3dDevice.RenderState.DestinationBlend = Blend.InvSourceAlpha;



            //d3dDevice.RenderState.ZBufferWriteEnable = false;
            //d3dDevice.SetTextureStageState(0, TextureStageStates.ColorOperation, (int)TextureOperation.BlendDiffuseAlpha);
            //d3dDevice.SetTextureStageState(0, TextureStageStates.ColorArgument1, (int)TextureArgument.Diffuse);
            //d3dDevice.SetTextureStageState(0, TextureStageStates.ColorArgument2, (int)TextureArgument.Current);
            //d3dDevice.SetTextureStageState(0, TextureStageStates.AlphaOperation, (int)TextureOperation.SelectArg1);
            //d3dDevice.SetTextureStageState(0, TextureStageStates.AlphaArgument1, (int)TextureArgument.Diffuse);
            //d3dDevice.SetTextureStageState(0, TextureStageStates.AlphaArgument2, (int)TextureArgument.Current);

            //d3dDevice.SetTextureStageState(1, TextureStageStates.ColorOperation, (int)TextureOperation.Disable);
            //d3dDevice.SetTextureStageState(1, TextureStageStates.AlphaOperation, (int)TextureOperation.Disable);



            //pDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
            //pDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
            //pDev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
            //pDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);


            if(m_PlotData.PlotType== ScatterplotType.Normal)
            d3dDevice.Transform.World = Matrix.Scaling(m_vPlotArea * (0.5f + m_bbAreaScale - 1.0f)) *
                Matrix.Translation(m_vPlotPosition.X, m_vPlotPosition.Y + m_vPlotArea.Y / 2, m_vPlotPosition.Z);
            else
                d3dDevice.Transform.World = Matrix.Scaling(m_vPlotArea * (0.5f + m_bbAreaScale - 1.0f)) *
                Matrix.Translation(m_vPlotPosition.X, m_vPlotPosition.Y + m_vPlotArea.Y / 2+1, m_vPlotPosition.Z);

            d3dDevice.VertexFormat = CustomVertex.PositionColored.Format;
            d3dDevice.SetStreamSource(0, m_vbPlotArea, 0);
            d3dDevice.Indices = m_ibPlotAreaBBLines;
            //d3dDevice.RenderState.AntiAliasedLineEnable = true;
            d3dDevice.DrawIndexedPrimitives(PrimitiveType.LineList, 0, 0, 8, 0, 12);
            //d3dDevice.RenderState.AntiAliasedLineEnable = false;

            if (!m_bRenderBoundingBox)
                return;


            d3dDevice.RenderState.AlphaBlendEnable = true;
            d3dDevice.RenderState.CullMode = Cull.Clockwise;
            d3dDevice.VertexFormat = CustomVertex.PositionColored.Format;
            d3dDevice.Indices = m_ibPlotAreaBBTriangles;
            d3dDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 8, 0, 12);




            d3dDevice.RenderState.AlphaBlendEnable = false;
            //d3dDevice.RenderState.ZBufferWriteEnable = true;


        }





      

        /// <summary>
        /// Renders grid on visible sides of the bounding box
        /// </summary>
        void RenderGrid()
        {
            if (m_PlotData == null) return;
            if (!m_PlotData.Settings.ShowGrid) return;

            d3dDevice.RenderState.ZBufferEnable = false;
            d3dDevice.RenderState.AntiAliasedLineEnable = true;
            d3dDevice.Transform.World = Matrix.Identity;
            d3dDevice.RenderState.Lighting = false;
            d3dDevice.RenderState.AlphaBlendEnable = true;
            d3dDevice.RenderState.SourceBlend = Blend.SourceAlpha;
            d3dDevice.RenderState.DestinationBlend = Blend.InvSourceAlpha;
            Vector3 viewDirection = m_vLookAt - m_vCameraPos;
            Vector3 toCamera, normal;

            Vector3 vbbPlotArea = m_vPlotArea * m_bbAreaScale * 1.04f;
            if (m_PlotData.PlotType!= ScatterplotType.BiPlot )
            {
                //left side
                if (m_PlotData.Settings.PlotProjectionType == ProjectionType.Perspective)
                    toCamera = m_vCameraPos - (m_vPlotPosition + new Vector3(-vbbPlotArea.X / 2, 0, 0));
                else
                {
                    toCamera = m_vCameraPos - m_vLookAt;
                }
                normal = new Vector3(1, 0, 0);
                if (Vector3.Dot(normal, toCamera) > 0)
                {
                    //side visible, draw grid

                    //intensity
                    for (int i = 0; i < m_YMarkerPositions.Count; i++)
                    {
                        RenderDashedLine(m_YMarkerPositions[i],
                            m_YMarkerPositions[i] + new Vector3(0, 0, -vbbPlotArea.Z));
                    }

                    for (int i = 0; i < m_ZMarkerPositions.Count; i++)
                    {
                        RenderDashedLine(m_ZMarkerPositions[i],
                            m_ZMarkerPositions[i] + new Vector3(0, vbbPlotArea.Y, 0));
                    }

                }


                //back side

                if (m_PlotData.Settings.PlotProjectionType == ProjectionType.Perspective)
                    toCamera = m_vCameraPos - (m_vPlotPosition + new Vector3(0, 0, -vbbPlotArea.Z / 2));
                else
                {
                    toCamera = m_vCameraPos - m_vLookAt;
                }
                normal = new Vector3(0, 0, 1);
                if (Vector3.Dot(normal, toCamera) > 0)
                {
                    //side visible, draw grid

                    //intensity
                    for (int i = 0; i < m_YMarkerPositions.Count; i++)
                    {
                        RenderDashedLine(m_YMarkerPositions[i] + new Vector3(0, 0, -vbbPlotArea.Z),
                            m_YMarkerPositions[i] + new Vector3(vbbPlotArea.X, 0, -vbbPlotArea.Z));
                    }

                    for (int i = 0; i < m_XMarkerPositions.Count; i++)
                    {
                        RenderDashedLine(m_XMarkerPositions[i] + new Vector3(0, 0, -vbbPlotArea.Z),
                            m_XMarkerPositions[i] + new Vector3(0, vbbPlotArea.Y + 0.5f, -vbbPlotArea.Z));
                    }

                }

                //right side

                if (m_PlotData.Settings.PlotProjectionType == ProjectionType.Perspective)
                    toCamera = m_vCameraPos - (m_vPlotPosition + new Vector3(vbbPlotArea.X / 2, 0, 0));
                else
                {
                    toCamera = m_vCameraPos - m_vLookAt;
                }
                normal = new Vector3(-1, 0, 0);
                if (Vector3.Dot(normal, toCamera) > 0)
                {
                    //side visible, draw grid

                    //intensity
                    for (int i = 0; i < m_YMarkerPositions.Count; i++)
                    {
                        RenderDashedLine(m_YMarkerPositions[i] + new Vector3(vbbPlotArea.X, 0, -vbbPlotArea.Z),
                            m_YMarkerPositions[i] + new Vector3(vbbPlotArea.X, 0, 0));
                    }

                    for (int i = 0; i < m_ZMarkerPositions.Count; i++)
                    {
                        RenderDashedLine(m_ZMarkerPositions[i] + new Vector3(vbbPlotArea.X, 0, 0),
                            m_ZMarkerPositions[i] + new Vector3(vbbPlotArea.X, vbbPlotArea.Y + 0.5f, 0));
                    }

                }

                //front side

                if (m_PlotData.Settings.PlotProjectionType == ProjectionType.Perspective)
                    toCamera = m_vCameraPos - (m_vPlotPosition + new Vector3(0, 0, vbbPlotArea.Z / 2));
                else
                {
                    toCamera = m_vCameraPos - m_vLookAt;
                }
                normal = new Vector3(0, 0, -1);
                if (Vector3.Dot(normal, toCamera) > 0)
                {
                    //side visible, draw grid

                    //intensity
                    for (int i = 0; i < m_YMarkerPositions.Count; i++)
                    {
                        RenderDashedLine(m_YMarkerPositions[i] + new Vector3(vbbPlotArea.X, 0, 0),
                            m_YMarkerPositions[i]);
                    }

                    for (int i = 0; i < m_XMarkerPositions.Count; i++)
                    {
                        RenderDashedLine(m_XMarkerPositions[i],
                            m_XMarkerPositions[i] + new Vector3(0, vbbPlotArea.Y, 0));
                    }

                }


                //grid on the ground
                //intensity
                for (int i = 0; i < m_XMarkerPositions.Count; i++)
                {
                    RenderDashedLine(m_XMarkerPositions[i],
                        m_XMarkerPositions[i] + new Vector3(0, 0, -vbbPlotArea.Z));
                }

                for (int i = 0; i < m_ZMarkerPositions.Count; i++)
                {
                    RenderDashedLine(m_ZMarkerPositions[i],
                        m_ZMarkerPositions[i] + new Vector3(vbbPlotArea.X, 0, 0));
                }
            }
            else
            {
                //grid XZ
                //intensity
                
                for (int i = 0; i < m_XMarkerPositions.Count; i++)
                {
                    for (int j = 0; j < m_YMarkerPositions.Count; j++)
                    {
                        //if (i == 2)
                        //    continue;
                        RenderDashedLine(m_XMarkerPositions[i] + new Vector3(0, m_YMarkerPositions[j].Y  +m_vPlotArea.Y / 3, 0),
                            m_XMarkerPositions[i] + new Vector3(0, m_YMarkerPositions[j].Y + m_vPlotArea.Y/3 , -vbbPlotArea.Z));
                    }
                }
                
                for (int i = 0; i < m_XMarkerPositions.Count; i++)
                {
                    for (int j = 0; j < m_ZMarkerPositions.Count; j++)
                    {
                        RenderDashedLine(m_XMarkerPositions[i] + new Vector3(0, 0, -vbbPlotArea.Z / 2 + m_ZMarkerPositions[j].Z),
                            m_XMarkerPositions[i] + new Vector3(0, vbbPlotArea.Y + 0.5f, -vbbPlotArea.Z / 2 + m_ZMarkerPositions[j].Z));
                    }
                } 

                for (int i = 0; i < m_YMarkerPositions.Count; i++)
                {
                    for (int j = 0; j < m_ZMarkerPositions.Count; j++)
                    {
                        RenderDashedLine(m_YMarkerPositions[i] + new Vector3(0, 0,-vbbPlotArea.Z / 2 + m_ZMarkerPositions[j].Z),
                            m_YMarkerPositions[i] + new Vector3(vbbPlotArea.X, 0,-vbbPlotArea.Z / 2 + m_ZMarkerPositions[j].Z));
                    }
                }
                /*
                for (int i = 0; i < m_ZMarkerPositions.Count; i++)
                {
                    //if (i == 2)
                    //    continue;
                    RenderDashedLine(m_ZMarkerPositions[i] + new Vector3(0, vbbPlotArea.Y / 2, 0),
                        m_ZMarkerPositions[i] + new Vector3(vbbPlotArea.X, vbbPlotArea.Y / 2, 0));
                }
                /*
                //grid XY
                //intensity
                for (int i = 0; i < m_YMarkerPositions.Count; i++)
                {
                    RenderDashedLine(m_YMarkerPositions[i] + new Vector3(0, 0, -vbbPlotArea.Z/2),
                        m_YMarkerPositions[i] + new Vector3(vbbPlotArea.X, 0, -vbbPlotArea.Z/2));
                }

                for (int i = 0; i < m_XMarkerPositions.Count; i++)
                {
                    RenderDashedLine(m_XMarkerPositions[i] + new Vector3(0, 0, -vbbPlotArea.Z/2),
                        m_XMarkerPositions[i] + new Vector3(0, vbbPlotArea.Y + 0.5f, -vbbPlotArea.Z/2));
                }

                //grid YZ
                //intensity
                //intensity
                for (int i = 0; i < m_YMarkerPositions.Count; i++)
                {
                    RenderDashedLine(m_YMarkerPositions[i] + new Vector3(vbbPlotArea.X/2, 0, -vbbPlotArea.Z),
                        m_YMarkerPositions[i] + new Vector3(vbbPlotArea.X/2, 0, 0));
                }

                for (int i = 0; i < m_ZMarkerPositions.Count; i++)
                {
                    RenderDashedLine(m_ZMarkerPositions[i] + new Vector3(vbbPlotArea.X/2, 0, 0),
                        m_ZMarkerPositions[i] + new Vector3(vbbPlotArea.X/2, vbbPlotArea.Y + 0.5f, 0));
                }
                */

            }
            d3dDevice.RenderState.ZBufferEnable = true;
            d3dDevice.RenderState.AlphaBlendEnable = false;
            d3dDevice.RenderState.AntiAliasedLineEnable = false;
        }


        /// <summary>
        /// Renders text with debugging info
        /// </summary>
        void RenderDebugText()
        {
#if !DEBUG
            return;
#endif
            m_debugFont.DrawText(null, "BackBufferSize:" + currentPresentParameters.BackBufferWidth +
                " x " + currentPresentParameters.BackBufferHeight + " Frame#:" + m_iFrameNumber +
            "RX:" + m_fCameraRotationX.ToString() + " RY:" + m_fCameraRotationY.ToString(), new Point(0, 0), Color.Red);

        }

        void RenderLegend()
        {
            if (m_PlotData == null || m_PlotData.PlotClasses == null || m_PlotData.Settings.ShowLegend == false || m_PlotData.PlotClasses.Count == 0) return;

            const int xStart = 10;
            const int yStart = 10;

            int legendWidth = 0;
            const int fontWidth = 8;
            const int fontHeight = 20;

            for (int i = 0; i < m_PlotData.PlotClasses.Count; i++)
            {
                if (m_PlotData.PlotClasses[i].ClassName.Length * fontWidth > legendWidth)
                    legendWidth = m_PlotData.PlotClasses[i].ClassName.Length * fontWidth;
            }
            legendWidth += 15;
            int legendHeight = m_PlotData.PlotClasses.Count * fontHeight;

            //draw rectangle
            d3dDevice.RenderState.ZBufferEnable = false;
            d3dDevice.RenderState.AlphaBlendEnable = true;
            d3dDevice.RenderState.SourceBlend = Blend.SourceAlpha;
            d3dDevice.RenderState.DestinationBlend = Blend.InvSourceAlpha;

            //m_spriteObject.Begin(SpriteFlags.None);
            //m_spriteObject.Draw2D(m_WhiteTexture, System.Drawing.Rectangle.Empty,
            //    new Rectangle(0,0,legendWidth,legendHeight), new Point(xStart, yStart), Color.FromArgb(150, 0, 0, 0));
            //m_spriteObject.End();
            m_spriteObject.Begin(SpriteFlags.None);

            m_spriteObject.Transform = Matrix.Transformation2D(new Vector2(), 0.0f,
                                        new Vector2(legendWidth / 2, legendHeight / 2), new Vector2(),
                                        0, new Vector2(xStart, yStart));
            m_spriteObject.Draw(m_WhiteTexture, System.Drawing.Rectangle.Empty, new Vector3(0, 0, 0), new Vector3(0, 0, 1), Color.FromArgb(150, 0, 0, 0));
            m_spriteObject.End();

            d3dDevice.RenderState.ZBufferEnable = true;
            d3dDevice.RenderState.AlphaBlendEnable = false;

            Line line = new Line(d3dDevice);

            line.Draw(new Vector2[] { new Vector2(xStart, yStart), new Vector2(xStart + legendWidth, yStart),
                new Vector2(xStart + legendWidth, yStart + legendHeight), new Vector2(xStart, yStart + legendHeight),new Vector2(xStart, yStart) },
                Color.LightGray);
            //if (m_GradientTexture == null) return;


            for (int i = 0; i < m_PlotData.PlotClasses.Count; i++)
            {
                m_LegendFont.DrawText(null, m_PlotData.PlotClasses[i].ClassName, new Point(xStart + 4, yStart + 14 * i + 3), m_PlotData.PlotClasses[i].ClassColor);

            }



        }

        void RenderLoadingScreen()
        {
            if (m_WhiteTexture == null) return;

            d3dDevice.RenderState.ZBufferEnable = false;
            d3dDevice.RenderState.AlphaBlendEnable = true;
            d3dDevice.RenderState.SourceBlend = Blend.SourceAlpha;
            d3dDevice.RenderState.DestinationBlend = Blend.InvSourceAlpha;
            m_spriteObject.Begin(SpriteFlags.None);

            m_spriteObject.Draw2D(m_WhiteTexture, System.Drawing.Rectangle.Empty,
                new Rectangle(0, 0, currentPresentParameters.BackBufferWidth, currentPresentParameters.BackBufferHeight), new Point(0, 0), 0, new Point(0, 0), Color.FromArgb(150, 0, 0, 0));

            m_spriteObject.End();

            d3dDevice.RenderState.ZBufferEnable = true;
            d3dDevice.RenderState.AlphaBlendEnable = false;
            m_LoadingFont.DrawText(null, "Loading...", new Point(currentPresentParameters.BackBufferWidth / 2 - 50, currentPresentParameters.BackBufferHeight / 2 - 15),
                Color.White);


        }

        void RenderErrorText()
        {
            if (m_WhiteTexture == null) return;

            d3dDevice.RenderState.ZBufferEnable = false;
            d3dDevice.RenderState.AlphaBlendEnable = true;
            d3dDevice.RenderState.SourceBlend = Blend.SourceAlpha;
            d3dDevice.RenderState.DestinationBlend = Blend.InvSourceAlpha;
            m_spriteObject.Begin(SpriteFlags.None);

            m_spriteObject.Draw2D(m_WhiteTexture, System.Drawing.Rectangle.Empty,
                new Rectangle(0, 0, currentPresentParameters.BackBufferWidth, currentPresentParameters.BackBufferHeight), new Point(0, 0), 0, new Point(0, 0), Color.FromArgb(150, 0, 0, 0));

            m_spriteObject.End();

            d3dDevice.RenderState.ZBufferEnable = true;
            d3dDevice.RenderState.AlphaBlendEnable = false;
            m_LoadingFont.DrawText(null, m_ErrorText, new Rectangle(0, 0, currentPresentParameters.BackBufferWidth, currentPresentParameters.BackBufferHeight), DrawTextFormat.Center,
                Color.White);


        }


        /// <summary>
        /// Renders the Plot
        /// </summary>
        void RenderPlot()
        {
            if (m_PlotData == null) return;
            d3dDevice.Transform.World = Matrix.Identity;



            Plane p0 = Plane.FromPointNormal(m_vPlotPosition + new Vector3(-m_vPlotArea.X * m_bbAreaScale / 2, 0, 0), new Vector3(1, 0, 0));
            Plane p1 = Plane.FromPointNormal(m_vPlotPosition + new Vector3(m_vPlotArea.X * m_bbAreaScale / 2, 0, 0), new Vector3(-1, 0, 0));
            Plane p2 = Plane.FromPointNormal(m_vPlotPosition + new Vector3(0, m_vPlotArea.Y / 2 - m_bbAreaScale * m_vPlotArea.Y / 2, 0), new Vector3(0, 1, 0));
            Plane p3 = Plane.FromPointNormal(m_vPlotPosition + new Vector3(0, m_bbAreaScale * m_vPlotArea.Y, 0), new Vector3(0, -1, 0));
            Plane p4 = Plane.FromPointNormal(m_vPlotPosition + new Vector3(0, 0, m_vPlotArea.Z * m_bbAreaScale / 2), new Vector3(0, 0, -1));
            Plane p5 = Plane.FromPointNormal(m_vPlotPosition + new Vector3(0, 0, -m_vPlotArea.Z * m_bbAreaScale / 2), new Vector3(0, 0, 1));

            d3dDevice.ClipPlanes[0].Plane = p0;
            d3dDevice.ClipPlanes[0].Enabled = true;
            d3dDevice.ClipPlanes[1].Plane = p1;
            d3dDevice.ClipPlanes[1].Enabled = true;
            d3dDevice.ClipPlanes[2].Plane = p2;
            d3dDevice.ClipPlanes[2].Enabled = true;
            d3dDevice.ClipPlanes[3].Plane = p3;
            d3dDevice.ClipPlanes[3].Enabled = true;
            d3dDevice.ClipPlanes[4].Plane = p4;
            d3dDevice.ClipPlanes[4].Enabled = true;
            d3dDevice.ClipPlanes[5].Plane = p5;
            d3dDevice.ClipPlanes[5].Enabled = true;

            //float fScale = 1.0f / m_PlotZoom.m_fMZSubset;


            if (m_PlotData.PlotType == ScatterplotType.Normal)
                RenderScatterplotData();
            else
                RenderBiplotData();

            d3dDevice.ClipPlanes[0].Enabled = false;
            d3dDevice.ClipPlanes[1].Enabled = false;
            d3dDevice.ClipPlanes[2].Enabled = false;
            d3dDevice.ClipPlanes[3].Enabled = false;
            d3dDevice.ClipPlanes[4].Enabled = false;
            d3dDevice.ClipPlanes[5].Enabled = false;


        }

        private void RenderBiplotData()
        {
            if (m_PlotData == null) return;
            d3dDevice.RenderState.Lighting = true;
            d3dDevice.RenderState.ZBufferEnable = true;
            d3dDevice.RenderState.ZBufferWriteEnable = true;

            d3dDevice.Lights[0].Type = LightType.Directional;
            d3dDevice.Lights[0].Diffuse = Color.White;
            d3dDevice.Lights[0].Ambient = Color.DarkGray;
            d3dDevice.Lights[0].Direction = new Vector3(0f, -0.3f, -1f);
            d3dDevice.Lights[0].Enabled = true;

            d3dDevice.RenderState.SourceBlend = Blend.SourceAlpha;
            d3dDevice.RenderState.DestinationBlend = Blend.InvSourceAlpha;
            d3dDevice.RenderState.AlphaBlendEnable = true;

            d3dDevice.RenderState.CullMode = Cull.None;

            Vector3 BiRange = new Vector3(2, 2, 2);
            Vector3 BiMin = new Vector3(-1, -1, -1);
            Vector3 center = new Vector3(-BiMin.X - BiRange.X / 2,
                    -BiMin.Y - BiRange.Y / 2 + (m_vPlotPosition.Y + m_vPlotArea.Y / 2) * 2 / m_vPlotArea.Y,
                    -BiMin.Z - BiRange.Z / 2);
            Material mat = new Material();

            Matrix transform = Matrix.Translation(center);



            transform *= Matrix.Scaling(m_vPlotArea.X / 2,
                                        m_vPlotArea.Y / 2,
                                        m_vPlotArea.Z / 2);

            m_PlotTransform = transform;

            center.X *= m_vPlotArea.X / 2;
            center.Y *= m_vPlotArea.Y / 2;
            center.Z *= m_vPlotArea.Z / 2;
            //Matrix plotposition = Matrix.Translation(m_vPlotPosition) * Matrix.Scaling(m_vPlotArea.X / (2 * m_PlotZoom.Subset), m_vPlotArea.Y / (2 * m_PlotZoom.Subset), m_vPlotArea.Z / (2 * m_PlotZoom.Subset));

            //transform *= plotposition;

            for (int i = 0; i < m_PlotData.PlotData.Count; i++)
            {
                
                Vector3 pos = m_PlotData.PlotData[i].Position;
                float max_abs = Math.Max(Math.Abs(pos.X), Math.Abs(pos.Y));
                max_abs = Math.Max(max_abs, Math.Abs(pos.Z));
                if (max_abs <= m_PlotData.Settings.CorrelationThreshold)
                    continue;
                CustomVertex.PositionOnly[] pointList = new CustomVertex.PositionOnly[2];
                pos.TransformCoordinate(transform);
                pointList[0] = new CustomVertex.PositionOnly(center);
                pointList[1] = new CustomVertex.PositionOnly(pos);

                mat.Ambient = Color.Black;
                mat.Diffuse = Color.Black;
                d3dDevice.Material = mat;
                d3dDevice.Transform.World = Matrix.Identity;
                d3dDevice.DrawUserPrimitives(PrimitiveType.LineList, 1, pointList);

                //draw single point
                if (m_bVertexSelected && pos == m_vSelectedPosition)
                {
                    mat.Ambient = Color.Yellow;
                    mat.Diffuse = Color.Yellow;
                }
                else
                {
                    mat.Ambient = Color.FromArgb(Color.Red.R / 4, Color.Red.G / 4, Color.Red.B / 4);
                    mat.Diffuse = Color.Red;
                }
                d3dDevice.Material = mat;



                if (m_PlotData.Settings.ShowCaseNames && pos != m_vSelectedPosition)
                {
                    Vector2 screenPos = WorldToScreen(pos);

                    if (m_PlotData.PlotData[i].CaseName != null)
                        m_axisFont.DrawText(null, m_PlotData.PlotData[i].CaseName, new Point((int)screenPos.X - 5 * m_PlotData.PlotData[i].CaseName.Length / 2, (int)screenPos.Y), Color.LightGray);

                }
                if (pos == m_vSelectedPosition)
                {
                    Vector2 screenPos = WorldToScreen(pos);

                    if (m_PlotData.PlotData[i].CaseName != null)
                        m_axisFont.DrawText(null, m_PlotData.PlotData[i].CaseName, new Point((int)screenPos.X - 5 * m_PlotData.PlotData[i].CaseName.Length / 2, (int)screenPos.Y - 13), Color.Black);

                }

                d3dDevice.Transform.World = Matrix.Translation(pos);
                m_PlotPointMesh.DrawSubset(0);
            }

            mat.Ambient = Color.FromArgb(50, Color.LightGray);
            mat.Diffuse = Color.FromArgb(50, Color.LightGray);
            d3dDevice.Material = mat;

            d3dDevice.Transform.World = transform;
            // Z-pass 
            d3dDevice.RenderState.ColorWriteEnable = 0;
            m_PlotSphereMesh.DrawSubset(0);
            // Drawing the sphere
            d3dDevice.RenderState.ColorWriteEnable = ColorWriteEnable.RedGreenBlueAlpha;
            m_PlotSphereMesh.DrawSubset(0);
            d3dDevice.RenderState.AlphaBlendEnable = false;

        }

        void RenderScatterplotData()
        {
            if (m_PlotData == null) return;
            d3dDevice.RenderState.Lighting = true;
            d3dDevice.RenderState.ZBufferEnable = true;
            d3dDevice.RenderState.ZBufferWriteEnable = true;

            d3dDevice.Lights[0].Type = LightType.Directional;
            d3dDevice.Lights[0].Diffuse = Color.White;
            d3dDevice.Lights[0].Ambient = Color.DarkGray;
            d3dDevice.Lights[0].Direction = new Vector3(0f, -0.3f, -1f);
            d3dDevice.Lights[0].Enabled = true;

            d3dDevice.RenderState.CullMode = Cull.None;

            Material mat = new Material();

            Matrix transform = Matrix.Translation(-m_PlotData.MinX - m_PlotData.XRange / 2 - (m_PlotZoom.XOffset + m_PlotZoom.Subset / 2 - 0.5f) * m_PlotData.XRange,
                    -m_PlotData.MinY - (m_PlotZoom.YOffset) * m_PlotData.YRange, -m_PlotData.MinZ - m_PlotData.ZRange / 2 - (m_PlotZoom.ZOffset + m_PlotZoom.Subset / 2 - 0.5f) * m_PlotData.ZRange) *
                    Matrix.Scaling(m_vPlotArea.X / (m_PlotData.XRange * m_PlotZoom.Subset), m_vPlotArea.Y / (m_PlotData.YRange * m_PlotZoom.Subset), m_vPlotArea.Z / (m_PlotData.ZRange * m_PlotZoom.Subset));

            m_PlotTransform = transform;

            for (int i = 0; i < m_PlotData.PlotData.Count; i++)
            {
                Vector3 pos = m_PlotData.PlotData[i].Position;
                pos.TransformCoordinate(transform);
                if (!(pos.X >= -1.01f * m_vPlotArea.X / 2 && pos.X <= 1.01f * m_vPlotArea.X / 2 &&
                    pos.Y >= -0.01f && pos.Y <= 1.01f * m_vPlotArea.Y &&
                    pos.Z >= 1.01f * -m_vPlotArea.Z / 2 && pos.Z <= 1.01f * m_vPlotArea.Z / 2)) continue;
                //draw single point
                if (m_bVertexSelected && m_PlotData.PlotData[i].Position == m_vSelectedData)
                {
                    mat.Ambient = Color.White;
                    mat.Diffuse = Color.White;
                }
                else if (m_PlotData.PlotData[i].caseClass != null)
                {
                    mat.Ambient = Color.FromArgb(255, m_PlotData.PlotData[i].caseClass.ClassColor.R / 2,
                        m_PlotData.PlotData[i].caseClass.ClassColor.G / 2,
                        m_PlotData.PlotData[i].caseClass.ClassColor.B / 2);
                    mat.Diffuse = m_PlotData.PlotData[i].caseClass.ClassColor;
                }
                else
                {
                    mat.Ambient = Color.Gray;
                    mat.Diffuse = Color.White;
                }
                d3dDevice.Material = mat;

                //pos += m_vPlotPosition;

                if (m_PlotData.Settings.ShowCaseNames)
                {
                    Vector2 screenPos = WorldToScreen(pos);

                    if (m_PlotData.PlotData[i].CaseName != null)
                        m_axisFont.DrawText(null, m_PlotData.PlotData[i].CaseName, new Point((int)screenPos.X - 5 * m_PlotData.PlotData[i].CaseName.Length / 2, (int)screenPos.Y), m_ColorFontCurrent);

                }
                else
                {
                    int a = 0;
                }


                d3dDevice.Transform.World = Matrix.Translation(pos);
                m_PlotPointMesh.DrawSubset(0);
            }
        }


        #endregion

        void ResetZoom()
        {
            m_PlotZoom.Subset = 1;
            m_PlotZoom.XOffset = 0;
            m_PlotZoom.YOffset = 0;
            m_PlotZoom.ZOffset = 0;
        }

        private int m_iCurrentDataZoom = 0;
        public void SetDataZoom(int zoomFactor)
        {
            if (d3dDevice == null) return;

            if (zoomFactor < 0)
                zoomFactor = 0;
            m_iCurrentDataZoom = zoomFactor;
            float fOldSubset = m_PlotZoom.Subset;
            m_PlotZoom.Subset = (float)Math.Pow(0.95f, zoomFactor);
            float fZ = fOldSubset - m_PlotZoom.Subset; ;

            const float fMinSubset = 0.05f;


            if (m_PlotZoom.Subset > 1)
            {
                m_PlotZoom.Subset = 1;
            }
            else if (m_PlotZoom.Subset < fMinSubset)
            {
                m_PlotZoom.Subset = fMinSubset;
            }
            else
            {
                if (!m_bVertexSelected)
                {
                    m_PlotZoom.XOffset += fZ / 2;
                    m_PlotZoom.YOffset += fZ / 2;
                    m_PlotZoom.ZOffset += fZ / 2;
                }
                else
                {
                    m_PlotZoom.XOffset += fZ * (m_vSelectedData.X - AxisMinX) / (AxisMaxX - AxisMinX);
                    m_PlotZoom.YOffset += fZ * (m_vSelectedData.Y - AxisMinY) / (AxisMaxY - AxisMinY);
                    m_PlotZoom.ZOffset += fZ * (m_vSelectedData.Z - AxisMinZ) / (AxisMaxZ - AxisMinZ);
                    //m_PlotZoom.XOffset += fZ * (m_vSelectedPosition.X + m_vPlotArea.X / 2) / m_vPlotArea.X;
                    //m_PlotZoom.YOffset += fZ * (m_vSelectedPosition.Y + m_vPlotArea.Y / 2) / m_vPlotArea.Y;
                    //m_PlotZoom.ZOffset += fZ * (m_vSelectedPosition.Z + m_vPlotArea.Z / 2) / m_vPlotArea.Z;
                }

            }


            if (m_PlotZoom.ZOffset < 0)
                m_PlotZoom.ZOffset = 0;

            if (m_PlotZoom.XOffset < 0)
                m_PlotZoom.XOffset = 0;

            if (m_PlotZoom.YOffset < 0)
                m_PlotZoom.YOffset = 0;


            if (m_PlotZoom.Subset + m_PlotZoom.ZOffset > 1)
                m_PlotZoom.ZOffset = 1 - m_PlotZoom.Subset;


            if (m_PlotZoom.Subset + m_PlotZoom.XOffset > 1)
                m_PlotZoom.XOffset = 1 - m_PlotZoom.Subset;

            if (m_PlotZoom.Subset + m_PlotZoom.YOffset > 1)
                m_PlotZoom.YOffset = 1 - m_PlotZoom.Subset;


            RenderD3D();

        }


        private void Plot3DControl_MouseMove(object sender, MouseEventArgs e)
        {
            if (d3dDevice == null) return;
            if (m_PlotData == null) return;
            //left mouse button rotates the plot

            if (e.Button == MouseButtons.Left)
            {

                //camera rotation
                m_fCameraRotationY += (-e.X + m_previousMousePosition.X) / m_fMouseRotateSensitivity;
                m_fCameraRotationX += (-e.Y + m_previousMousePosition.Y) / m_fMouseRotateSensitivity;

                if (m_PlotData != null && m_PlotData.Settings.PlotProjectionType == ProjectionType.Orthographic)
                {
                    if (m_fCameraRotationX > 0.085f)
                        m_fCameraRotationX = 0.085f;
                }
                else
                {
                    if (m_fCameraRotationX > 0.13f)
                        m_fCameraRotationX = 0.13f;
                }

                if (m_fCameraRotationX < -Math.PI / 2 + 0.1f)
                    m_fCameraRotationX = -(float)Math.PI / 2 + 0.1f;

                if (m_fCameraRotationY > 2 * Math.PI)
                    m_fCameraRotationY -= 2 * (float)Math.PI;
                if (m_fCameraRotationY < 0)
                    m_fCameraRotationY += 2 * (float)Math.PI;
                m_previousMousePosition = e.Location;





                SetCamera();
                RenderD3D();
            }
            else if (e.Button == MouseButtons.Right)
            {


            }
            else if (e.Button == MouseButtons.None)
            {
                //Vector3 ray0 = Vector3.Unproject(new Vector3(e.X, e.Y, 0), d3dDevice.Viewport, m_ProjectionMatrix, m_ViewMatrix, m_PlotTransform);
                //Vector3 ray1 = Vector3.Unproject(new Vector3(e.X, e.Y, 1), d3dDevice.Viewport, m_ProjectionMatrix, m_ViewMatrix, m_PlotTransform);




                bool oldSelected = m_bVertexSelected;
                Vector3 oldPos = m_vSelectedData;
                m_bVertexSelected = SelectVertex(e.X, e.Y, out m_vSelectedPosition, out m_vSelectedData);

                if (m_bVertexSelected != oldSelected || m_vSelectedData != oldPos)
                    RenderD3D();

            }
        }



        private void Plot3DControl_MouseDown(object sender, MouseEventArgs e)
        {
            if (d3dDevice == null) return;

            m_previousMousePosition = e.Location;
        }

        private void Plot3DControl_MouseUp(object sender, MouseEventArgs e)
        {
            if (d3dDevice == null) return;
        }

        void Scatterplot3DControl_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            m_bVertexSelected = SelectVertex(e.X, e.Y, out m_vSelectedPosition, out m_vSelectedData);
            if (m_PlotData.PlotType == ScatterplotType.Normal)
            {
                if (m_bVertexSelected)
                {
                    float fCenterX = (m_vSelectedData.X - m_PlotData.MinX) / m_PlotData.XRange;
                    float fCenterY = (m_vSelectedData.Y - m_PlotData.MinY) / m_PlotData.YRange;
                    float fCenterZ = (m_vSelectedData.Z - m_PlotData.MinZ) / m_PlotData.ZRange;

                    m_PlotZoom.XOffset = fCenterX - m_PlotZoom.Subset / 2;
                    m_PlotZoom.YOffset = fCenterY - m_PlotZoom.Subset / 2;
                    m_PlotZoom.ZOffset = fCenterZ - m_PlotZoom.Subset / 2;


                    if (m_PlotZoom.ZOffset < 0)
                        m_PlotZoom.ZOffset = 0;

                    if (m_PlotZoom.XOffset < 0)
                        m_PlotZoom.XOffset = 0;

                    if (m_PlotZoom.YOffset < 0)
                        m_PlotZoom.YOffset = 0;


                    if (m_PlotZoom.Subset + m_PlotZoom.ZOffset > 1)
                        m_PlotZoom.ZOffset = 1 - m_PlotZoom.Subset;


                    if (m_PlotZoom.Subset + m_PlotZoom.XOffset > 1)
                        m_PlotZoom.XOffset = 1 - m_PlotZoom.Subset;

                    if (m_PlotZoom.Subset + m_PlotZoom.YOffset > 1)
                        m_PlotZoom.YOffset = 1 - m_PlotZoom.Subset;

                }
            }
            else
            {
                if(m_bVertexSelected)
                {
//                     m_vLookAt = m_vSelectedData;
//                     m_vInitialLookAt = m_vSelectedData;
//                     SetProjection();
//                     SetCamera();
                }
            }
            RenderD3D();
        }

        /// <summary>
        /// Sets camera zoom, in percents.
        /// </summary>
        /// <param name="zoom">Zoom in percents - 0 means no zoom, 100 means maximum possible zoom.</param>
        public void SetCameraZoom(int zoom)
        {
            CurrentCameraDistance = m_fMaxCameraDistance - (m_fMaxCameraDistance - m_fMinCameraDistance) * zoom / 100.0f;
            Refresh();
        }

        private void zoomInToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SetDataZoom(m_iCurrentDataZoom + 10);
            (Parent.Parent as WidgetScatterplot3D).SetZoom(m_iCurrentDataZoom);
        }

        private void zoomOutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SetDataZoom(m_iCurrentDataZoom - 10);
            (Parent.Parent as WidgetScatterplot3D).SetZoom(m_iCurrentDataZoom);
        }

        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            WidgetScatterplot3D parent = (WidgetScatterplot3D)Parent.Parent;
            parent.SaveScreenshot();
        }

        internal void SetBkgColor(Color color)
        {
            if (color != m_ColorBgNormal)
            {
                m_ColorBgNormal = color;
                m_ColorBgCurrent = color;
                Refresh();
            }            
        }

        public Color GetBkColor()
        {
            return m_ColorBgCurrent;
        }
    }
}
